package com.sf.fy.uav.applet.utils.exception;

import com.sf.fy.uav.common.exception.BusinessException;
import com.sf.fy.uav.common.utils.ResultCode;
import com.sf.fy.uav.common.utils.Rs;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.net.BindException;
import java.util.List;

/**
 * @author LTQ
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(RuntimeException.class)
    public Rs globalException(HttpServletResponse response, RuntimeException ex) {
        log.info("GlobalExceptionHandler...");
        log.info("错误代码：" + response.getStatus());
        String msg;
        if (ObjectUtils.isEmpty(ex.getCause())) {
            msg = ex.getMessage();
            log.info(ex.getMessage());
        } else {
            msg = ex.getCause().getMessage();
            log.info(ex.getCause().getMessage());
        }
        return Rs.failed(msg);
    }

    /**
     * 缺少参数异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {MissingServletRequestParameterException.class})
    @ResponseBody
    public Rs paramMiss(MissingServletRequestParameterException e) {
        log.error("", e);
        return Rs.failed(e.getParameterName() + "is required !");
    }


    /**
     * 参数校验异常
     *
     * @return
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    @ResponseBody
    public Rs paramValid(MethodArgumentNotValidException e) {
        log.error("", e);
        //获取异常信息
        BindingResult exceptions = e.getBindingResult();
        //判断异常中是否有错误信息，如果存在就使用异常中的消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                //这里列出了全部错误参数，按正常逻辑取第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                return Rs.failed(fieldError.getCode(), fieldError.getDefaultMessage());
            }
        }
        return Rs.failed("参数异常");
    }


    @ResponseBody
    @ExceptionHandler(BusinessException.class)
    public Rs globalException(HttpServletResponse response, BusinessException ex) {
        log.info("GlobalExceptionHandler...");
        log.info("错误代码：" + response.getStatus());
        log.info(ex.getMessage());
        ResultCode resultCode = new ResultCode() {
            @Override
            public Integer getCode() {
                return ex.getError().getErrCode();
            }
        };
        return Rs.failed(resultCode, ex.getErrDetail());
    }

    /**
     * 数据校验全局处理
     * BindException是@Valid使用校验失败时产生的异常
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public Rs BindExceptionHandler(BindException e) {

        //捕获数据校验异常
        Rs resultInfo = new Rs();
        resultInfo.setCode(500);
        //获取实体类定义的校验注解字段上的message作为异常信息，@NotBlank(message = "用户密码不能为空！")异常信息即为"用户密码不能为空！"
        resultInfo.setMsg(e.getMessage());
        return resultInfo;
    }

    /**
     * 全局异常处理
     * 如果设置了特定异常处理，全局异常处理可作为兜底异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Rs exceptionHandler(Exception e) {
        Rs resultInfo = new Rs();
        //一旦进入这个方法说明有异常，这是固定的异常信息
        resultInfo.setCode(100);
        resultInfo.setMsg("操作异常！");
        return resultInfo;
    }
}
